//
// Created on 2025/11/21.
// Author 秦光磊.
#include "drawbridge/draw_component.h"
#include "constant/constant.h"
#include "drawbase/draw_base.h"
#include "render/egl_core.h"
#include <cmath>
#include <hilog/log.h>
/**
 * 画核外电子排布括号，上下两个右椭圆弧，中间一缺口，填写能级电子数
 * blocks表示核外电子的括弧分割的块数（上下分割的快数一致，当前默认为7），usedBlocks表示当前能级层占用的快数，模拟核外电子的原括弧随能级变化的场景，同时该值的大小也表示了当前能级
 * @param eglCore 核心绘制载体，负责具体的绘制操作
 * @param startVector 括号的起始位置，由于括号是来自椭圆上的一段弧形，所以这个起始位置就是对应椭圆的中心坐标
 * @param startSize 单独的一个点大小，一般是3
 * @param parenWidth 括号宽度
 * @param parenHeight 括号高度
 * @param electronsSum 电子数
 * @param drawColor 绘制颜色
 * @param colorSize 颜色大小，一般是4，即rgba
 * @param blocks 总块数，实际是总能级数，这里需要默认7
 * @param usedBlocks 本次需要使用的块数，实际是当前能级，范围是[1,7]
 * @param geometryAttribute
 * 几何参数用到geometryAttribute[0]:geometryAttribute[0]为1表示虚线，为3表示实线
 * 几何参数用到geometryAttribute[1]:geometryAttribute[1]为1表示画小图，为2表示画大图
 * @param attrSize 由于用到geometryAttribute[1]，所以最小是2
 * @return
 */
bool DrawComponent::DrawElectronDistributionParen(EGLCore *eglCore, std::vector<GLfloat> &startVector, int startSize,
                                                  float parenWidth, float parenHeight, int electronsSum,
                                                  GLfloat drawColor[4], int colorSize, int blocks, int usedBlocks,
                                                  int *geometryAttribute, int attrSize) {
    OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_PRINT_DOMAIN, "DrawComponent", "%{public}s start.", __func__);
    if ((startSize < 3) || (colorSize < 4) || (attrSize < 2)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent",
                     "%{public}s 参数检查不对。startSize:%{public}d,colorSize:%{public}d,attrSize:%{public}d.",
                     __func__, startSize, colorSize, attrSize);
        return false;
    }
    if (startVector.size() < startSize) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent",
                     "%{public}s startVector大小不对。startVector.size():%zu.", __func__, startVector.size());
        return false;
    }
    if (eglCore == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent", "%{public}s eglCore为nullptr.", __func__);
        return false;
    }
    if (geometryAttribute == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent", "%{public}s geometryAttribute为nullptr.",
                     __func__);
        return false;
    }
    OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_PRINT_DOMAIN, "DrawComponent", "%{public}s 参数值parenWidth：%{public}f,parenHeight:%{public}f.",
                 __func__, parenWidth, parenHeight);
    if ((parenWidth <= 0) || (parenHeight <= 0)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent", "%{public}s parenWidth与parenHeight不能为0.", __func__);
        return false;
    }
    // 先拆解开始位置坐标，便于编码
    GLfloat startX = startVector[0];
    GLfloat startY = startVector[1];
    GLfloat startZ = startVector[2];
    // 先画圆括号，圆括号将采用椭圆绘制
    // 椭圆的中心，x坐标为startX，y坐标为startY，z坐标为startZ
    // 椭圆的a为width，椭圆b为height / 2
    // 画一个中间缺口的半椭圆，将采取画两个部分椭圆方式
    // 确定两个椭圆弧所占有的大小，这里采用度数
    float radianSize = (float)(M_PI * 80.0f / 180.0f);

    // 75度分为blocks份,每个快大小
    if (blocks == 0)
        blocks = 7; // 容错处理，分割块数不能等于0，若等于0，按照默认值7处理，否则按照上送的值处理
    float cellBlocksSize = radianSize / blocks;

    // 上边括弧与下边括弧的的起始角度
    float startAngleUp = (blocks - usedBlocks) * cellBlocksSize; // 上括弧的起始角度随占用快数不同而不同
    float startAngleDown = (float)M_PI - radianSize; // 下括弧的起始角度只与整个弧度大小有关
    // 括弧跨度的角度
    float arcAngle = usedBlocks * cellBlocksSize;

    // 画第一个椭圆弧,采用实线绘制
    DrawBase *drawBase = new DrawBase();
    drawBase->DrawOneEllipseArc(eglCore, parenWidth, parenHeight / 2.0f, startVector, 3, drawColor, colorSize,
                                startAngleUp, arcAngle, geometryAttribute, attrSize);


    // 画第二个椭圆弧,采用实线绘制
    drawBase->DrawOneEllipseArc(eglCore, parenWidth, parenHeight / 2.0f, startVector, 3, drawColor, colorSize,
                                startAngleDown, arcAngle, geometryAttribute, attrSize);

    // 生成缺口处大小位置参数
    // 缺口处y坐标，一上一下，相减则可计算出缺口尺寸
    float indentationUpY = (float)((parenHeight / 2.0f) * cos(radianSize) + startY);
    float indentationDownY = (float)((parenHeight / 2.0f) * cos(startAngleDown) + startY);
    // 计算处缺口处填写数字的尺寸
    float scale = (indentationUpY - indentationDownY) * 2.0f / 3.0f;
    // 缺口处x坐标，根据数字的大小来，数字为个位数与数字为两位数字，x坐标不一样，要保证数字的整体在缺口的中间
    float indentationX;
    // 中心到缺口处的距离
    float distanceCenterToIndentation = (float)(parenWidth * sin(radianSize));
    // 每个数字的宽度不同，需要适配
    if (electronsSum < 10) {
        // 1位数字处理
        if (electronsSum == 1) {
            // 数字1特殊处理，因为数字1的宽度是特别处理的
            indentationX = distanceCenterToIndentation + startX;
        } else {
            // 其它个位数字，x正常获取
            indentationX = distanceCenterToIndentation + startX - scale * 3.0f / 12.0f;
        }
    } else {
        // 两位数字（要么一位数字，要么两位数字，因为每个亚层最多容纳32个电子）
        // 数字的高度已经确定为scale，那么数字的宽度为scale / 2f，则在正常x坐标的基础上减去scale / 2f就可以
        indentationX = distanceCenterToIndentation + startX - scale / 2.0f;
        // 如果为11，此时占用宽度比较小，向右推进一部分适配
        if (electronsSum == 11) {
            indentationX = indentationX + scale * 0.3f;
        }
    }
    // 释放资源
    delete drawBase;
    drawBase = nullptr;
    return true;
}

/**
 * 画水平框，平均分为divisionCount格，divisionCount大于等于1
 * @param eglCore eglCore 核心绘制载体，负责具体的绘制操作
 * @param startVector 水平框的起始位置
 * @param startSize 起始位置坐标大小，一般是3个数字
 * @param horizontalBoxWidth 水平框总体宽度
 * @param horizontalBoxHeight 水平框总体高度
 * @param divisionCount 水平框被分割的格子数
 * @param drawColor 绘制颜色
 * @param colorSize 绘制颜色坐标大小，一般是3个数字
 * @param geometryAttribute
 * 第1个，geometryAttribute[0]代表绘制线条的方式：虚线条-1，实线首位相连-2，实线条-3，三角形-4，三角形带-5，扇区-6，点-其它值
 * 第2个，geometryAttribute[1]代表绘制的图大小：1代表小图，采集点数少；2代表大图，采集点数多。采集的点能少就少，提高性能
 * @param attrSize 因为用到geometryAttribute[1]，所以大小最小是2
 * @return
 */
bool DrawComponent::DrawHorizontalBox(EGLCore *eglCore, std::vector<GLfloat> &startVector, int startSize,
                                      float horizontalBoxWidth, float horizontalBoxHeight, int divisionCount,
                                      GLfloat drawColor[4], int colorSize, int *geometryAttribute, int attrSize) {
    OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_PRINT_DOMAIN, "DrawComponent", "%{public}s start.", __func__);
    if ((startSize < 3) || (colorSize < 4) || (attrSize < 2)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent",
                     "%{public}s 参数检查不对。startSize:%{public}d,colorSize:%{public}d,attrSize:%{public}d.",
                     __func__, startSize, colorSize, attrSize);
        return false;
    }
    if (startVector.size() < startSize) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent",
                     "%{public}s startVector大小不对。startVector.size():%zu.", __func__, startVector.size());
        return false;
    }
    if (eglCore == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent", "%{public}s eglCore为nullptr.", __func__);
        return false;
    }
    if (geometryAttribute == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent", "%{public}s geometryAttribute为nullptr.",
                     __func__);
        return false;
    }
    // 先分解起始坐标，便于编码
    float startX = startVector[0];
    float startY = startVector[1];
    float startZ = startVector[2];
    // 基础绘制实例
    DrawBase *drawBase = new DrawBase();
    // 分割快数不能小于等于0，否则将置为1
    if (divisionCount <= 0) {
        divisionCount = 1;
    }
    // 每格的宽度,总宽度与总分割数之比就是每个单元格的宽度
    float widthForCell = horizontalBoxWidth / divisionCount;
    // 画分割的竖线，最开始竖线的x坐标
    float verticalLineX;
    verticalLineX = startX;
    float i;
    std::vector<GLfloat> fromVertices;
    std::vector<GLfloat> toVertices;
    for (i = 0; i < divisionCount; i++) {
        fromVertices.clear();
        toVertices.clear();
        // 竖线上顶点：x坐标为verticalLineX，y坐标为horizontalBoxHeight / 2.0f
        fromVertices.push_back(verticalLineX);
        fromVertices.push_back(startY + horizontalBoxHeight / 2.0f);
        fromVertices.push_back(startZ);
        // 竖线下顶点：x坐标为verticalLineX，y坐标为horizontalBoxHeight / 2.0f
        toVertices.push_back(verticalLineX);
        toVertices.push_back(startY - horizontalBoxHeight / 2.0f);
        toVertices.push_back(startZ);
        // 上下连线绘制一条线段
        bool drawLine = drawBase->DrawLineSegment(eglCore, fromVertices, fromVertices.size(), toVertices,
                                                  toVertices.size(), drawColor, colorSize, geometryAttribute, attrSize);
        if (!drawLine) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent",
                         "%{public}s drawLine绘制失败，具体见drawBase->DrawLineSegment日志.", __func__);
            return false;
        }
        // 准备下一条绘制
        verticalLineX = verticalLineX + widthForCell;
    }
    // 此时还剩余最后一条竖线没有画，由于分割不一定是整数，此时单独画最后一条线，
    fromVertices.clear();
    toVertices.clear();
    // x坐标为 startX + horizontalBoxWidth，y与z跟之前的保持一致
    fromVertices.push_back(startX + horizontalBoxWidth);
    fromVertices.push_back(startY + horizontalBoxHeight / 2.0f);
    fromVertices.push_back(startZ);
    toVertices.push_back(startX + horizontalBoxWidth);
    toVertices.push_back(startY - horizontalBoxHeight / 2.0f);
    toVertices.push_back(startZ);
    bool drawLineLast = drawBase->DrawLineSegment(eglCore, fromVertices, fromVertices.size(), toVertices,
                                                  toVertices.size(), drawColor, colorSize, geometryAttribute, attrSize);
    if (!drawLineLast) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent",
                     "%{public}s drawLineLast绘制失败，具体见drawBase->DrawLineSegment日志.", __func__);
        return false;
    }
    // 画两条水平线
    // 上水平线左顶点，x坐标startX，y坐标startY + horizontalBoxHeight / 2.0f
    // 上水平线右顶点，x坐标startX + horizontalBoxWidth，y坐标startY + horizontalBoxHeight / 2.0f
    fromVertices.clear();
    toVertices.clear();
    fromVertices.push_back(startX);
    fromVertices.push_back(startY + horizontalBoxHeight / 2.0f);
    fromVertices.push_back(startZ);
    toVertices.push_back(startX + horizontalBoxWidth);
    toVertices.push_back(startY + horizontalBoxHeight / 2.0f);
    toVertices.push_back(startZ);
    bool drawLineUp = drawBase->DrawLineSegment(eglCore, fromVertices, fromVertices.size(), toVertices,
                                                toVertices.size(), drawColor, colorSize, geometryAttribute, attrSize);
    if (!drawLineUp) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent",
                     "%{public}s drawLineUp绘制失败，具体见drawBase->DrawLineSegment日志.", __func__);
        return false;
    }
    // 下水平线左顶点，x坐标startX，y坐标startY - horizontalBoxHeight / 2.0f
    // 下水平线右顶点，x坐标startX + horizontalBoxWidth，y坐标startY - horizontalBoxHeight / 2.0f
    fromVertices.clear();
    toVertices.clear();
    fromVertices.push_back(startX);
    fromVertices.push_back(startY - horizontalBoxHeight / 2.0f);
    fromVertices.push_back(startZ);
    toVertices.push_back(startX + horizontalBoxWidth);
    toVertices.push_back(startY - horizontalBoxHeight / 2.0f);
    toVertices.push_back(startZ);
    bool drawLineDown = drawBase->DrawLineSegment(eglCore, fromVertices, fromVertices.size(), toVertices,
                                                  toVertices.size(), drawColor, colorSize, geometryAttribute, attrSize);
    if (!drawLineDown) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "DrawComponent",
                     "%{public}s drawLineDown绘制失败，具体见drawBase->DrawLineSegment日志.", __func__);
        return false;
    }
    // 释放资源
    delete drawBase;
    drawBase = nullptr;
    return true;
}
